<?php
class GameCore {
    private $redisManager;
    private $cardManager;
    private $logger;

    public function __construct() {
        $this->redisManager = new RedisManager();
        $this->cardManager = new CardManager();
        $date = date('YmdHis');
        $this->logger = new Logger('logs/log'.$date.'.log');
    }

    /**
     * 创建新游戏
     * @param $gameId int 游戏ID
     * @param $initialCards int 初始牌数
     * @param $discardChances  int 换牌次数
     * @param $playChances int 出牌次数
     * @param $targetScore int 目标分数
     * @return array
     * @throws Exception
     */
    public function startNewGame($gameId, $initialCards = 10, $discardChances = 3, $playChances = 5, $targetScore = 1000) {
        // 创建牌堆
        $deck = $this->cardManager->createDeck();

        // 洗牌
        $deck = $this->cardManager->shuffleDeck($deck);
        $this->logger->info('洗牌后牌堆信息: ' . json_encode($deck, JSON_UNESCAPED_UNICODE));

        // 抽取初始牌
        $hand = $this->cardManager->drawCards($deck, $initialCards);
        $this->logger->info('抽牌后手牌信息: ' . json_encode($hand, JSON_UNESCAPED_UNICODE));
        // 减少牌池中被抽取的牌
        $deck = $this->cardManager->removeCards($deck, $hand);
        $this->logger->info('移除手牌后的牌池信息: ' . json_encode($deck, JSON_UNESCAPED_UNICODE));

        $gameData = [
            'hand' => $hand,
            'deck' => $deck,
            'discard_chances' => $discardChances,
            'play_chances' => $playChances,
            'total_score' => 0,
            'target_score' => $targetScore,
            'status' => 'playing',
            'created_at' => time()
        ];

        $this->redisManager->setGameData($gameId, 'game_state', $gameData);
        return $gameData;
    }

    /**
     * 换牌
     * @param $gameId int 游戏ID
     * @param $handCardIndexes int[] 手牌索引数组
     * @param $deckCardIndexes int[] 牌堆中要替换的牌索引数组
     * @return array
     * @throws Exception
     */
    public function discardCards($gameId, $handCardIndexes, $deckCardIndexes) {
        $gameData = $this->redisManager->getGameData($gameId, 'game_state');

        if ($gameData['discard_chances'] <= 0) {
            throw new Exception("没有换牌次数了");
        }

        if (count($handCardIndexes) > 3) {
            throw new Exception("每次最多只能换3张牌");
        }

        if (count($handCardIndexes) != count($deckCardIndexes)) {
            throw new Exception("手牌索引数量必须与牌堆索引数量一致");
        }

        // 检查索引有效性
        foreach ($handCardIndexes as $index) {
            if (!isset($gameData['hand'][$index])) {
                throw new Exception("无效的手牌索引: " . $index);
            }
        }

        foreach ($deckCardIndexes as $index) {
            if (!isset($gameData['deck'][$index])) {
                throw new Exception("无效的牌堆索引: " . $index);
            }
        }

        // 执行换牌操作
        for ($i = 0; $i < count($handCardIndexes); $i++) {
            $handIndex = $handCardIndexes[$i];
            $deckIndex = $deckCardIndexes[$i];

            // 交换手牌和牌堆中的牌
            $tempCard = $gameData['hand'][$handIndex];
            $gameData['hand'][$handIndex] = $gameData['deck'][$deckIndex];
            $gameData['deck'][$deckIndex] = $tempCard;
        }

        $gameData['discard_chances']--;

        $this->redisManager->setGameData($gameId, 'game_state', $gameData);
        return $gameData;
    }


    /**
     * 出牌并计算得分（支持最多5张牌，按牌型计算倍率）
     * @param string $gameId 牌局ID
     * @param string $playerId 玩家ID
     * @param array $cardIndexes 手牌索引数组（最多5个）
     * @return array 包含牌型、基础分、倍率和总分的数组
     * @throws Exception
     */
    public function playCards(string $gameId, string $playerId, array $cardIndexes): array {
        $this->logger->info("玩家 {$playerId} 尝试出牌，牌局ID: {$gameId}，牌索引: " . json_encode($cardIndexes));

        try {
            // 检查牌索引数量（最少1张）
            if (count($cardIndexes) < 1) {
                $this->logger->error("出牌数量不能为0");
                throw new Exception("出牌数量不能为0");
            }
            // 检查牌索引数量（最多5张）
            if (count($cardIndexes) > 5) {
                $this->logger->error("出牌数量超过限制（最多5张）");
                throw new Exception("出牌数量超过限制");
            }

            // 获取游戏数据
            $gameData = $this->redisManager->getGameData($gameId, 'game_state');
            $this->logger->info("获取游戏数据成功: " . json_encode($gameData, JSON_UNESCAPED_UNICODE));

            // 检查牌索引是否有效
            foreach ($cardIndexes as $index) {
                if (!isset($gameData['hand'][$index])) {
                    $this->logger->error("牌索引 {$index} 无效");
                    throw new Exception("牌索引无效");
                }
            }

            // 提取选中的牌
            $playedCards = [];
            foreach ($cardIndexes as $index) {
                $playedCards[] = $gameData['hand'][$index];
            }

            // 计算牌型和得分
            // 检查是否为有效牌型或单牌
            $scoreCalculator = new ScoreCalculator();
            $scoreResult = $scoreCalculator->calculateScore($gameId, $playedCards);

            // 如果牌型为高牌且出牌数量大于1，则不允许出牌
            if ($scoreResult['hand_type'] === '高牌' && count($cardIndexes) > 1) {
                $this->logger->error("无效的出牌组合：非牌型且非单牌");
                throw new Exception("无效的出牌组合：非牌型且非单牌");
            }


            // 从手牌中移除已出的牌（从后往前移除，避免索引错乱）
            rsort($cardIndexes);
            foreach ($cardIndexes as $index) {
                array_splice($gameData['hand'], $index, 1);
            }

            // 减少出牌次数
            $gameData['play_chances']--;
            // 增加总分
            $gameData['total_score'] += $scoreResult['total_score'];
            // 检查是否达到目标分数
            if ($gameData['total_score'] >= $gameData['target_score']) {
                $gameData['status'] = 'finished';
            }

            // 更新游戏数据
            $this->redisManager->setGameData($gameId, 'game_state', $gameData);
            $this->logger->info("牌已从手牌移除，更新后的游戏数据: " . json_encode($gameData, JSON_UNESCAPED_UNICODE));

            return [
                'hand_type' => $scoreResult['hand_type'],
                'base_score' => $scoreResult['base_score'],
                'multiplier' => $scoreResult['multiplier'],
                'total_score' => $scoreResult['total_score'],
                'played_cards' => $playedCards
            ];
        } catch (Exception $e) {
            $this->logger->error("出牌时发生异常: " . $e->getMessage());
            throw $e;
        }
    }


    public function getGameState($gameId) {
        return $this->redisManager->getGameData($gameId, 'game_state');
    }

    /**
     * 创建自定义手牌用于测试
     * @param array $customCards 自定义牌组数组
     * @param string $gameId 游戏ID
     * @param int $discardChances 换牌次数（可选，默认为3）
     * @param int $playChances 出牌次数（可选，默认为5）
     * @param int $targetScore 目标分数（可选，默认为1000）
     * @return array 包含自定义手牌的游戏数据
     * @throws Exception
     */
    public function createCustomHandForTest(
        array $customCards,
        string $gameId,
        int $discardChances = 3,
        int $playChances = 5,
        int $targetScore = 1000
    ): array {
        // 验证自定义牌组格式
        foreach ($customCards as $card) {
            if (!isset($card['suit'], $card['rank'], $card['value'], $card['id'])) {
                throw new Exception("自定义牌组格式错误，必须包含 suit、rank、value 和 id 字段");
            }
        }

        // 创建游戏数据
        $gameData = [
            'hand' => $customCards,
            'deck' => [], // 牌堆为空（测试时不需要牌堆）
            'discard_chances' => $discardChances,
            'play_chances' => $playChances,
            'total_score' => 0,
            'target_score' => $targetScore,
            'status' => 'playing',
            'created_at' => time()
        ];

        // 保存到 Redis（可选）
        $this->redisManager->setGameData($gameId, 'game_state', $gameData);
        $this->logger->info("自定义手牌测试数据已创建: " . json_encode($gameData, JSON_UNESCAPED_UNICODE));

        return $gameData;
    }

}
?>